/*************************************************************************
                           Box  -  description
                             -------------------
    début                : 28 déc. 2009
    copyright            : (C) 2009 par nico
 *************************************************************************/

//---------- Interface de la classe <Box> (fichier Box.h) ------
#ifndef PMBOX_H_
#define PMBOX_H_

//--------------------------------------------------- Interfaces utilisées
#include <string>
#include <set>
#include <iostream>
#include "AbstractBox.h"
#include "Port_in.h"
#include "pmElement.h"
//------------------------------------------------------------- Constantes

//------------------------------------------------------------------ Types

//------------------------------------------------------------------------
// Rôle de la classe <Box>
//
//
//------------------------------------------------------------------------
template <class in_type = double, class out_type = in_type> class pmBox
: public AbstractBox
{
	//----------------------------------------------------------------- PUBLIC

public:
	//----------------------------------------------------- Méthodes publiques
	virtual bool Compute(){return false;};
	// main function of the box, computes using the entries (in and params)
	// and put the results in the m_elements member

	std::set<AbstractBox*> GetNextBoxes();
	// return the a set of pointers to the boxes connected to this one's outputs

	bool ConnectInput(std::string name, pmElement<in_type>* input);
	// setup the port_in (m_inputs) found by it's name
	bool ConnectInput(unsigned index, pmElement<in_type>* input);
	// idem, finding the port_in with an index instead

	// the following two methods are more intended for pipelines but can be used
	// by with kind of box if needed
	pmElement<out_type>* GetResult(unsigned Index = 0);
	// returns a reference to the result of one of the outputs
	pmElement<out_type>* GetResult(std::string outputName);
	// idem, finding the output with it's name

	//virtual std::string GetType();

	//-------------------------------------------- Constructeurs - destructeur
	pmBox (int nbInputs, int nbOutputs, int nbParams );
	// pmBox (){}; //TODO
	virtual ~pmBox ( );

protected:
	//----------------------------------------------------- Méthodes protégées
	//----------------------------------------------------- Attributs protégés

	Port_in<in_type>* m_inputs; //an array of port_in
	pmElement<out_type>** m_outputs; //an array of pointers to Element

	//Param* m_params;
	unsigned m_nbOutputs;
	unsigned m_nbInputs;
	unsigned m_nbParams;
	std::set<AbstractBox*> m_nextBoxes;
	// TODO: what exactely happens when copying an std::set?
};

//--------------------------- Autres définitions dépendantes de <Box>





/********************************************************************
 *		Implementation
 *
 *********************************************************************/

using namespace std;

//--------------------------------------------------------- Public methods




template <class in_type, class out_type>
set<AbstractBox*> pmBox<in_type, out_type>::GetNextBoxes()
{
	return m_nextBoxes;
}


template <class in_type, class out_type>
bool pmBox<in_type, out_type>::ConnectInput(string name, pmElement<in_type>* input)
{
	for(unsigned i = 0; i < m_nbInputs; ++i)
	{
		if(m_inputs[i].name == name)
		{
			m_inputs[i].SetElementPtr(input);
			return true;
		}
	}

	return false;
}

template <class in_type, class out_type>
bool pmBox<in_type, out_type>::ConnectInput(unsigned index, pmElement<in_type>* input)
{
	if(index < m_nbInputs)
	{
		m_inputs[index].SetElementPtr(input);
		return true;
	}
	else
	{
		return false; //invalid index
	}
}

template <class in_type, class out_type>
pmElement<out_type>* pmBox<in_type, out_type>::GetResult(unsigned index)
{
#ifdef appDEBUG
cout << "appel de GetResult " << index << endl;
#endif
	if(index < m_nbOutputs)
	{
#ifdef appDEBUG
cout << "...index correct " << endl;
#endif
		return m_outputs[index];
	}
	else
	{
		cerr << "erreur! index incorrect dans la methode pmBox.GetResult()" << endl;
		return NULL; //invalid index
	}
}

template <class in_type, class out_type>
pmElement<out_type>* pmBox<in_type, out_type>::GetResult(std::string outputName)
{
	for(int i = 0; i < m_nbOutputs; ++i)
	{
		if(m_outputs[i]->GetName() == outputName)
		{
			return m_outputs[i];
		}
	}

	return NULL;
}

//-------------------------------------------- Constructors - destructor
template <class in_type, class out_type>
pmBox<in_type, out_type>::pmBox(int nbInputs, int nbOutputs, int nbParams )
{
	cout << "construction de pmBox" << endl;
	m_nbInputs = nbInputs;
	m_nbOutputs = nbOutputs;
	m_nbParams = nbParams;

	m_inputs = new Port_in<in_type>[nbInputs];
}

template <class in_type, class out_type>
pmBox<in_type, out_type>::~pmBox ( )
{
	for(unsigned i = 0; i < m_nbOutputs; ++i)
		delete m_outputs[i];

#ifdef appDEBUG
	cout << "<Box>'s destructor called" << endl;
#endif
}



#endif // BOX_H_
